home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / tcpuser.c < prev    next >
C/C++ Source or Header  |  1991-06-03  |  9KB  |  380 lines

  1. /* User calls to TCP
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include "timer.h"
  7. #include "mbuf.h"
  8. #include "netuser.h"
  9. #include "socket.h"
  10. #include "internet.h"
  11. #include "tcp.h"
  12. #include "ip.h"
  13. #include "icmp.h"
  14. #include "proc.h"
  15.  
  16. int16 Tcp_window = DEF_WND;
  17.  
  18. struct tcb *
  19. open_tcp(lsocket,fsocket,mode,window,r_upcall,t_upcall,s_upcall,tos,user)
  20. struct socket *lsocket;    /* Local socket */
  21. struct socket *fsocket;    /* Remote socket */
  22. int mode;        /* Active/passive/server */
  23. int16 window;        /* Receive window (and send buffer) sizes */
  24. void (*r_upcall)();    /* Function to call when data arrives */
  25. void (*t_upcall)();    /* Function to call when ok to send more data */
  26. void (*s_upcall)();    /* Function to call when connection state changes */
  27. int tos;
  28. int user;        /* User linkage area */
  29. {
  30.     struct connection conn;
  31.     register struct tcb *tcb;
  32.  
  33.     if(lsocket == NULLSOCK){
  34.         Net_error = INVALID;
  35.         return NULLTCB;
  36.     }
  37.     conn.local.address = lsocket->address;
  38.     conn.local.port = lsocket->port;
  39.     if(fsocket != NULLSOCK){
  40.         conn.remote.address = fsocket->address;
  41.         conn.remote.port = fsocket->port;
  42.     } else {
  43.         conn.remote.address = 0;
  44.         conn.remote.port = 0;
  45.     }
  46.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  47.         if((tcb = create_tcb(&conn)) == NULLTCB){
  48.             Net_error = NO_MEM;
  49.             return NULLTCB;
  50.         }
  51.     } else if(tcb->state != TCP_LISTEN){
  52.         Net_error = CON_EXISTS;
  53.         return NULLTCB;
  54.     }
  55.     tcb->user = user;
  56.     if(window != 0)
  57.         tcb->window = tcb->rcv.wnd = window;
  58.     else
  59.         tcb->window = tcb->rcv.wnd = Tcp_window;
  60.     tcb->snd.wnd = 1;    /* Allow space for sending a SYN */
  61.     tcb->r_upcall = r_upcall;
  62.     tcb->t_upcall = t_upcall;
  63.     tcb->s_upcall = s_upcall;
  64.     tcb->tos = tos;
  65.     switch(mode){
  66.     case TCP_SERVER:
  67.         tcb->flags.clone = 1;
  68.     case TCP_PASSIVE:    /* Note fall-thru */
  69.         setstate(tcb,TCP_LISTEN);
  70.         break;
  71.     case TCP_ACTIVE:
  72.         /* Send SYN, go into TCP_SYN_SENT state */
  73.         tcb->flags.active = 1;
  74.         send_syn(tcb);
  75.         setstate(tcb,TCP_SYN_SENT);
  76.         tcp_output(tcb);
  77.         break;
  78.     }
  79.     return tcb;
  80. }
  81. /* User send routine */
  82. int
  83. send_tcp(tcb,bp)
  84. register struct tcb *tcb;
  85. struct mbuf *bp;
  86. {
  87.     int16 cnt;
  88.  
  89.     if(tcb == NULLTCB || bp == NULLBUF){
  90.         free_p(bp);
  91.         Net_error = INVALID;
  92.         return -1;
  93.     }
  94.     cnt = len_p(bp);
  95.     switch(tcb->state){
  96.     case TCP_CLOSED:
  97.         free_p(bp);
  98.         Net_error = NO_CONN;
  99.         return -1;
  100.     case TCP_LISTEN:
  101.         if(tcb->conn.remote.address == 0 && tcb->conn.remote.port == 0){
  102.             /* Save data for later */
  103.             append(&tcb->sndq,bp);
  104.             tcb->sndcnt += cnt;
  105.             break;
  106.         }        
  107.         /* Change state from passive to active */
  108.         tcb->flags.active = 1;
  109.         send_syn(tcb);
  110.         setstate(tcb,TCP_SYN_SENT);    /* Note fall-thru */
  111.     case TCP_SYN_SENT:
  112.     case TCP_SYN_RECEIVED:
  113.     case TCP_ESTABLISHED:
  114.     case TCP_CLOSE_WAIT:
  115.         append(&tcb->sndq,bp);
  116.         tcb->sndcnt += cnt;
  117.         tcp_output(tcb);
  118.         break;
  119.     case TCP_FINWAIT1:
  120.     case TCP_FINWAIT2:
  121.     case TCP_CLOSING:
  122.     case TCP_LAST_ACK:
  123.     case TCP_TIME_WAIT:
  124.         free_p(bp);
  125.         Net_error = CON_CLOS;
  126.         return -1;
  127.     }
  128.     return (int)cnt;
  129. }
  130. /* User receive routine */
  131. int
  132. recv_tcp(tcb,bpp,cnt)
  133. register struct tcb *tcb;
  134. struct mbuf **bpp;
  135. int16 cnt;
  136. {
  137.     if(tcb == NULLTCB || bpp == (struct mbuf **)NULL){
  138.         Net_error = INVALID;
  139.         return -1;
  140.     }
  141.     if(tcb->rcvcnt == 0){
  142.         /* If there's nothing on the queue, our action depends on what state
  143.          * we're in (i.e., whether or not we're expecting any more data).
  144.          * If no more data is expected, then simply return 0; this is
  145.          * interpreted as "end of file". Otherwise return -1.
  146.          */
  147.         switch(tcb->state){
  148.         case TCP_LISTEN:
  149.         case TCP_SYN_SENT:
  150.         case TCP_SYN_RECEIVED:
  151.         case TCP_ESTABLISHED:
  152.         case TCP_FINWAIT1:
  153.         case TCP_FINWAIT2:
  154.             Net_error = WOULDBLK;
  155.             return -1;
  156.         case TCP_CLOSED:
  157.         case TCP_CLOSE_WAIT:
  158.         case TCP_CLOSING:
  159.         case TCP_LAST_ACK:
  160.         case TCP_TIME_WAIT:
  161.             *bpp = NULLBUF;
  162.             return 0;
  163.         }
  164.     }
  165.     /* cnt == 0 means "I want it all" */
  166.     if(cnt == 0)
  167.         cnt = tcb->rcvcnt;
  168.     /* See if the user can take all of it */
  169.     if(tcb->rcvcnt <= cnt){
  170.         cnt = tcb->rcvcnt;
  171.         *bpp = tcb->rcvq;
  172.         tcb->rcvq = NULLBUF;
  173.     } else {
  174.         *bpp = ambufw(cnt);
  175.         pullup(&tcb->rcvq,(*bpp)->data,cnt);
  176.         (*bpp)->cnt = cnt;
  177.     }
  178.     tcb->rcvcnt -= cnt;
  179.     tcb->rcv.wnd += cnt;
  180.     /* Do a window update if it was closed */
  181.     if(cnt == tcb->rcv.wnd){
  182.         tcb->flags.force = 1;
  183.         tcp_output(tcb);
  184.     }
  185.     return (int)cnt;
  186. }
  187. /* This really means "I have no more data to send". It only closes the
  188.  * connection in one direction, and we can continue to receive data
  189.  * indefinitely.
  190.  */
  191. int
  192. close_tcp(tcb)
  193. register struct tcb *tcb;
  194. {
  195.     if(tcb == NULLTCB){
  196.         Net_error = INVALID;
  197.         return -1;
  198.     }
  199.     switch(tcb->state){
  200.     case TCP_CLOSED:
  201.         return 0;    /* Unlikely */
  202.     case TCP_LISTEN:
  203.     case TCP_SYN_SENT:
  204.         close_self(tcb,NORMAL);
  205.         return 0;
  206.     case TCP_SYN_RECEIVED:
  207.     case TCP_ESTABLISHED:
  208.         tcb->sndcnt++;
  209.         tcb->snd.nxt++;
  210.         setstate(tcb,TCP_FINWAIT1);
  211.         tcp_output(tcb);
  212.         return 0;
  213.     case TCP_CLOSE_WAIT:
  214.         tcb->sndcnt++;
  215.         tcb->snd.nxt++;
  216.         setstate(tcb,TCP_LAST_ACK);
  217.         tcp_output(tcb);
  218.         return 0;
  219.     case TCP_FINWAIT1:
  220.     case TCP_FINWAIT2:
  221.     case TCP_CLOSING:
  222.     case TCP_LAST_ACK:
  223.     case TCP_TIME_WAIT:
  224.         Net_error = CON_CLOS;
  225.         return -1;
  226.     }
  227.     return -1;    /* "Can't happen" */
  228. }
  229. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  230.  * not in the TCP_CLOSED state. This function should normally be called by the
  231.  * user only in response to a state change upcall to TCP_CLOSED state.
  232.  */
  233. int
  234. del_tcp(conn)
  235. struct tcb *conn;
  236. {
  237.     register struct tcb *tcb;
  238.     struct tcb *tcblast = NULLTCB;
  239.     struct reseq *rp,*rp1;
  240.  
  241.     /* Remove from list */
  242.     for(tcb=Tcbs;tcb != NULLTCB;tcblast = tcb,tcb = tcb->next)
  243.         if(tcb == conn)
  244.             break;
  245.     if(tcb == NULLTCB){
  246.         Net_error = INVALID;
  247.         return -1;    /* conn was NULL, or not on list */ 
  248.     }
  249.     if(tcblast != NULLTCB)
  250.         tcblast->next = tcb->next;
  251.     else
  252.         Tcbs = tcb->next;    /* was first on list */
  253.  
  254.     stop_timer(&tcb->timer);
  255.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  256.         rp1 = rp->next;
  257.         free_p(rp->bp);
  258.         free((char *)rp);
  259.     }
  260.     tcb->reseq = NULLRESEQ;
  261.     free_p(tcb->rcvq);
  262.     free_p(tcb->sndq);
  263.     free((char *)tcb);
  264.     return 0;
  265. }
  266. /* Return 1 if arg is a valid TCB, 0 otherwise */
  267. int
  268. tcpval(tcb)
  269. struct tcb *tcb;
  270. {
  271.     register struct tcb *tcb1;
  272.  
  273.     if(tcb == NULLTCB)
  274.         return 0;    /* Null pointer can't be valid */
  275.     for(tcb1=Tcbs;tcb1 != NULLTCB;tcb1 = tcb1->next){
  276.         if(tcb1 == tcb)
  277.             return 1;
  278.     }
  279.     return 0;
  280. }
  281. /* Kick a particular TCP connection */
  282. int
  283. kick_tcp(tcb)
  284. register struct tcb *tcb;
  285. {
  286.     if(!tcpval(tcb))
  287.         return -1;
  288.     tcb->flags.force = 1;    /* Send ACK even if no data */
  289.     tcp_timeout(tcb);
  290.     return 0;
  291. }
  292. /* Kick all TCP connections to specified address; return number kicked */
  293. int
  294. kick(addr)
  295. int32 addr;
  296. {
  297.     register struct tcb *tcb;
  298.     int cnt = 0;
  299.  
  300.     for(tcb=Tcbs;tcb != NULLTCB;tcb = tcb->next){
  301.         if(tcb->conn.remote.address == addr){
  302.             kick_tcp(tcb);
  303.             cnt++;
  304.         }
  305.     }
  306.     return cnt;
  307. }
  308. /* Clear all TCP connections */
  309. void
  310. reset_all()
  311. {
  312.     register struct tcb *tcb;
  313.  
  314.     for(tcb=Tcbs;tcb != NULLTCB;tcb = tcb->next)
  315.         reset_tcp(tcb);
  316.  
  317.     pwait(NULL);    /* Let the RSTs go forth */
  318. }
  319. void
  320. reset_tcp(tcb)
  321. register struct tcb *tcb;
  322. {
  323.     struct tcp fakeseg;
  324.     struct ip fakeip;
  325.  
  326.     if(tcb == NULLTCB)
  327.         return;
  328.     if(tcb->state != TCP_LISTEN){
  329.         /* Compose a fake segment with just enough info to generate the
  330.          * correct RST reply
  331.          */
  332.         memset((char *)&fakeseg,0,sizeof(fakeseg));
  333.         memset((char *)&fakeip,0,sizeof(fakeip));
  334.         fakeseg.dest = tcb->conn.local.port;
  335.         fakeseg.source = tcb->conn.remote.port;
  336.         fakeseg.flags.ack = 1;
  337.         /* Here we try to pick a sequence number with the greatest likelihood
  338.          * of being in his receive window.
  339.          */
  340.         fakeseg.ack = tcb->snd.nxt + tcb->snd.wnd - 1;
  341.         fakeip.dest = tcb->conn.local.address;
  342.         fakeip.source = tcb->conn.remote.address;
  343.         fakeip.tos = tcb->tos;
  344.         reset(&fakeip,&fakeseg);
  345.     }
  346.     close_self(tcb,RESET);
  347. }
  348. #ifdef    notused
  349. /* Return character string corresponding to a TCP well-known port, or
  350.  * the decimal number if unknown.
  351.  */
  352. char *
  353. tcp_port(n)
  354. int16 n;
  355. {
  356.     static char buf[32];
  357.  
  358.     switch(n){
  359.     case IPPORT_ECHO:
  360.         return "echo";
  361.     case IPPORT_DISCARD:
  362.         return "discard";
  363.     case IPPORT_FTPD:
  364.         return "ftp_data";
  365.     case IPPORT_FTP:
  366.         return "ftp";    
  367.     case IPPORT_TELNET:
  368.         return "telnet";
  369.     case IPPORT_SMTP:
  370.         return "smtp";
  371.     case IPPORT_POP:
  372.         return "pop";
  373.     default:
  374.         sprintf(buf,"%u",n);
  375.         return buf;
  376.     }
  377. }
  378. #endif
  379.  
  380.